Seam Carving in Julia
x
1
md"# Seam Carving in Julia"Functions
xxxxxxxxxx1
1
using Images, ImageView, ImageFiltering, Statistics, ImageMagick, PlutoUIbrightness (generic function with 1 method)x
1
# Convert RGB to brigthness2
function brightness(img_element::AbstractRGB)3
return mean((img_element.r + img_element.g + img_element.b))4
endfind_energy (generic function with 1 method)xxxxxxxxxx6
1
# Find energy, how important a pixel is to the image to us.2
function find_energy(img)3
energy_x = imfilter(brightness.(img), Kernel.sobel()[2])4
energy_y = imfilter(brightness.(img), Kernel.sobel()[1])5
6
return sqrt.(energy_x.^2 + energy_y.^2)7
endnormalize_greyness (generic function with 1 method)xxxxxxxxxx5
1
# To help view energy image, normalize values to 0-12
function normalize_greyness(array)3
max, _ = findmax(array)4
array = array./max5
return array6
endgrey_to_rgb (generic function with 1 method)x
1
# Convert a value to RGB to view arrays as images2
function grey_to_rgb(brigthness)::RGB3
return RGB(brigthness, brigthness, brigthness)4
endfind_seam_at (generic function with 1 method)xxxxxxxxxx10
1
# Finds the seam of least energy starting at given position2
function find_seam_at(next_elements, element)3
seam = zeros(Int, size(next_elements)[1])4
seam[1] = element5
6
for i = 2 :length(seam)7
seam[i] = seam[i-1] + next_elements[i, seam[i-1]]8
end9
10
return seam11
endfind_seam (generic function with 1 method)x
1
# Finds the best starting point and the seam from there2
function find_seam(energy)3
energy_map, next_elements = find_energy_map(energy)4
5
_, min_element = findmin(energy_map[1, :])6
7
return find_seam_at(next_elements, min_element)8
endfind_energy_map (generic function with 1 method)x
1
# Calculate the combined energy needed for each pixel from bottom to top2
function find_energy_map(energy)3
energy_map = zeros(size(energy))4
energy_map[ end, : ] = energy[ end, : ]5
6
next_elements = zeros(Int, size(energy))7
8
for i = size(energy)[1]-1 :-1:19
for j = 1 :size(energy)[2]10
left = max(1, j-1)11
right = min(j+1, size(energy)[2])12
13
local_energy, next_element = findmin(energy_map[i+1, left:right])14
energy_map[i,j] = local_energy + energy[i,j]15
16
next_elements[i,j] = next_element - 217
18
if left == 119
next_elements[i,j] += 120
end21
end22
end23
24
return energy_map, next_elements25
enddraw_seam (generic function with 1 method)x
1
function draw_seam(image, seam)2
image_with_seam = copy(image)3
for i = 1 : size(image_with_seam)[1]4
image_with_seam[i, seam[i]] = RGB(1, 0, 0)5
end6
7
return image_with_seam8
endremove_seam (generic function with 1 method)seam_carving (generic function with 1 method)x
1
function seam_carving(img, res)2
if res < 0 || res > size(img)[2]3
error("resolution not acceptable")4
end5
6
for i = (1:size(img)[2] - res)7
energy = find_energy(img)8
seam = find_seam(energy)9
img = remove_seam(img, seam)10
end11
return img12
endget_all_carved (generic function with 1 method)xxxxxxxxxx16
1
# Make all carved variants of the original image2
function get_all_carved(img, amount)3
4
if(amount < 0 || amount > size(img)[2])5
error("amount not acceptable")6
end7
8
all_images = []9
10
for i = (1:amount)11
energy = find_energy(img)12
seam = find_seam(energy)13
img = remove_seam(img, seam)14
push!(all_images, img)15
end16
return all_images17
endExamples
The original imagex
1
begin2
test_image = imresize(load("fox.jpg"), ratio=1/4.5)3
test_image = RGB{Float32}.(test_image)4
end459
675
x
1
size(test_image)459×675 Array{Float64,2}:
0.08230626182890809 0.03924633733582069 … 0.12013708121153048
0.08204016971261124 0.03615509192693736 0.1452321975682269
0.06117055721409237 0.07197040239680258 0.08148767262441961
0.1579527126513256 0.13794121945113755 0.05316306337434861
0.14057949647072956 0.07945411130085152 0.03812833195152889
0.21019070310238272 0.12611102359351106 … 0.16439778998489007
0.15806071985941766 0.05101811349756884 0.09896866880767466
⋮ ⋱
0.030956177996254306 0.03615507091560697 0.062391724730204975
0.06907769979945161 0.03448138488543452 0.0576724554581597
0.023529440164585358 0.02977717948065177 … 0.04000427991459951
0.04742507232365957 0.05030185791220897 0.057107305327577386
0.02630661388029809 0.03553835112719368 0.027116291064753127
0.024956750583578716 0.037203320918664774 0.04185369598012464x
1
energy = find_energy(test_image)This image below shows the "energy" or how important each pixel isxxxxxxxxxx1
1
energy_image = grey_to_rgb.(energy)459×675 Array{Float64,2}:
13.4415 13.3322 13.4144 13.4028 … 5.53075 5.49632 5.52851
13.4258 13.3592 13.293 13.3202 5.44132 5.40837 5.46554
13.3532 13.3438 13.323 13.2763 5.42115 5.32031 5.36379
13.3927 13.292 13.2718 13.2658 5.30259 5.32483 5.28231
13.4433 13.2347 13.1541 13.1492 5.29658 5.22914 5.23736
13.4577 13.3027 13.1553 13.1291 … 5.16706 5.19923 5.22769
13.3546 13.2475 13.1766 13.0791 5.03396 5.06329 5.20093
⋮ ⋱
0.14147 0.136973 0.145926 0.113835 0.13022 0.143386 0.195931
0.15812 0.110514 0.100818 0.103997 0.0959613 0.133539 0.176819
0.109384 0.0890423 0.0760325 0.0661278 … 0.0894212 0.119147 0.137979
0.0961168 0.0858545 0.0592651 0.0642783 0.0850369 0.0979748 0.0989295
0.0512634 0.0486917 0.0355526 0.0694598 0.0518985 0.0478337 0.0418222
0.0249568 0.0372033 0.0131534 0.0587131 0.00623912 0.0147059 0.0418537459×675 Array{Int64,2}:
1 2 0 -1 0 -1 1 0 1 1 1 … 0 -1 0 -1 1 0 -1 1 0 -1
1 2 1 0 1 0 1 0 -1 1 1 -1 1 1 1 0 1 0 -1 0 -1
1 2 1 1 1 0 -1 -1 -1 1 1 -1 -1 1 1 0 -1 1 0 1 0
1 2 1 0 1 1 0 -1 -1 -1 1 -1 1 0 -1 -1 0 -1 1 0 -1
1 2 1 0 -1 1 1 0 -1 -1 1 -1 0 -1 -1 1 1 0 -1 -1 -1
1 2 1 0 1 1 1 1 1 0 -1 … 1 0 -1 -1 1 1 1 0 -1 -1
1 1 1 1 0 1 1 0 -1 1 1 0 -1 -1 0 1 1 0 -1 -1 -1
⋮ ⋮ ⋮ ⋱ ⋮ ⋮
1 2 0 1 0 -1 1 0 1 1 0 0 -1 -1 -1 0 -1 0 -1 -1 -1
1 2 1 0 -1 1 0 -1 1 0 -1 -1 -1 -1 -1 -1 0 -1 0 -1 -1
1 2 0 -1 1 0 -1 -1 1 0 -1 … 0 -1 -1 -1 -1 0 -1 0 -1 -1
1 2 0 -1 1 1 0 -1 1 1 0 -1 -1 -1 -1 -1 1 0 1 1 0
0 2 0 -1 -1 1 0 -1 -1 1 0 -1 0 -1 0 -1 1 1 0 -1 -1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0xxxxxxxxxx1
1
energy_map, next_elements = find_energy_map(energy)This image below shows the the combined energy needed for a pixel at that position.xxxxxxxxxx4
1
begin2
normalized = normalize_greyness(energy_map)3
energy_map_img = grey_to_rgb.(normalized)4
end647
647
648
647
648
648
647
647
647
647
647
646
647
648
648
649
650
650
650
651
652
651
651
652
652
653
654
653
654
655
656
657
656
655
655
655
655
656
657
658
664
663
663
663
663
664
664
665
664
664
xxxxxxxxxx1
1
best_seam = find_seam(energy)Here the first best seam marked in redxxxxxxxxxx1
1
image_with_best_seam = draw_seam(test_image, best_seam)